import { AntDesignTheme, DocumentObject, useCommandManager } from '@amcax/base';
import { DraggableModal } from '@app-cad/common/components/draggable-modal/DraggableModal';
import { SKETCH_EVENT } from '@app-cad/common/Constants';
import { docMgr, userEvents } from '@app-cad/module';
import { Button, ConfigProvider } from 'antd';
import {
  FC,
  MouseEvent,
  useEffect,
  useLayoutEffect,
  useMemo,
  useReducer,
  useRef,
  useState,
} from 'react';
import { contextMenu } from 'react-contexify';
import { RelationObjectItemCMenu } from './content-menu';
import { RelationObjectItem } from './relation-object-item';
import { RelationsEvents, RelationsMenuProps } from './types';

interface RelationsDialogProps {
  open: boolean;
  onClose: () => void;
  documentObject: DocumentObject;
}

const relationObjectItemMenuId = 'relation-object-item-menu';

export const RelationsDialog: FC<RelationsDialogProps> = ({
  open,
  onClose,
  documentObject,
}) => {
  const { currentCmd } = useCommandManager();

  // refs for DOM elements
  const prelinkRefs = useRef<(HTMLDivElement | null)[]>([]);
  const objectRef = useRef<HTMLDivElement | null>(null);
  const outlinkRefs = useRef<(HTMLDivElement | null)[]>([]);
  // force update for drawing lines after render
  const [, forceUpdate] = useReducer((x) => x + 1, 0);

  useEffect(() => {
    const abortController = new AbortController();
    userEvents
      .on(
        RelationsEvents.ShowMenu,
        ({
          documentObject,
          selectedDxids,
          event,
        }: RelationsMenuProps & {
          event: MouseEvent;
        }) => {
          const modalContent = document.querySelector('.ant-modal-content');
          const rect = modalContent?.getBoundingClientRect();
          const x = event.clientX - (rect?.left ?? 0);
          const y = event.clientY - (rect?.top ?? 0);

          contextMenu.show({
            id: relationObjectItemMenuId,
            event,
            props: {
              documentObject,
              selectedDxids,
            },
            position: { x, y },
          });
        },
        abortController.signal,
      )
      .on(
        SKETCH_EVENT.SKETCH_ENTER_EDIT,
        () => onClose(),
        abortController.signal,
      );

    return () => abortController.abort();
  }, []);

  useEffect(() => {
    if (currentCmd) {
      onClose();
    }
  }, [currentCmd]);

  useEffect(() => {
    // update after DOM rendered
    forceUpdate();
  }, [open, documentObject]);

  // Helper to get center of a DOM element's side
  const getSideCenter = (el: HTMLDivElement | null, side: 'left' | 'right') => {
    if (!el) {
      return { x: 0, y: 0 };
    }
    const rect = el.getBoundingClientRect();
    const x = side === 'left' ? rect.left : rect.right;
    const y = rect.top + rect.height / 2;
    return { x, y };
  };

  const prelinks: string[] = useMemo(
    () => documentObject?.prelinks || [],
    [documentObject],
  );
  const outlinks: string[] = useMemo(
    () => documentObject?.outlinks || [],
    [documentObject],
  );

  const [selectedDxids, setSelectedDxids] = useState<string[]>(
    [documentObject?.dxid].filter(Boolean),
  );

  // Reset selection when dialog opens or documentObject changes
  useEffect(() => {
    setSelectedDxids([documentObject?.dxid].filter(Boolean));
  }, [open, documentObject]);

  const handleSelect = (dxid: string, event: MouseEvent<HTMLSpanElement>) => {
    let newSelected: string[];
    const isCtrl = event.ctrlKey;

    if (isCtrl) {
      if (selectedDxids.includes(dxid)) {
        newSelected = selectedDxids.filter((id) => id !== dxid);
      } else {
        newSelected = [...selectedDxids, dxid];
      }
    } else {
      newSelected = [dxid];
    }
    setSelectedDxids(newSelected);

    const selectedObjects = newSelected
      .map((id) => docMgr.getDocumentObjectById(id))
      .filter(Boolean);
    userEvents.emit(RelationsEvents.ClickObjects, selectedObjects);
  };

  // For absolute positioning of SVG overlay
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [containerRect, setContainerRect] = useState<DOMRect | null>(null);

  useLayoutEffect(() => {
    let raf: number;

    function updateRect() {
      if (containerRef.current) {
        const rect = containerRef.current.getBoundingClientRect();
        if (rect.width > 0 && rect.height > 0) {
          setContainerRect(rect);
        } else {
          raf = requestAnimationFrame(updateRect);
        }
      }
    }

    updateRect();
    return () => raf && cancelAnimationFrame(raf);
  }, [open, documentObject]);

  // Draw lines between prelinks -> object, object -> outlinks
  const lines: { x1: number; y1: number; x2: number; y2: number }[] = [];
  if (containerRect && objectRef.current) {
    prelinkRefs.current.forEach((el) => {
      if (el) {
        const from = getSideCenter(el, 'right');
        const to = getSideCenter(objectRef.current, 'left');
        lines.push({
          x1: from.x - containerRect.left,
          y1: from.y - containerRect.top,
          x2: to.x - containerRect.left,
          y2: to.y - containerRect.top,
        });
      }
    });
    outlinkRefs.current.forEach((el) => {
      if (el) {
        const from = getSideCenter(objectRef.current, 'right');
        const to = getSideCenter(el, 'left');
        lines.push({
          x1: from.x - containerRect.left,
          y1: from.y - containerRect.top,
          x2: to.x - containerRect.left,
          y2: to.y - containerRect.top,
        });
      }
    });
  }

  if (!open) {
    // Don't render anything if dialog is closed to reset the selected object
    return null;
  }

  const handleColumnScroll = () => {
    forceUpdate();
  };

  return (
    <ConfigProvider theme={AntDesignTheme}>
      <DraggableModal
        open={open}
        width={480}
        title='父级与子级'
        classNames={{
          wrapper: 'pointer-events-none',
        }}
        mask={false}
        onCancel={onClose}
        footer={<Button onClick={onClose}>关闭</Button>}
        maskClosable={false}
      >
        <div
          ref={containerRef}
          className='relative h-80 flex flex-row border-t border-b  border-[#e7eaed] bg-[#f9fafb] items-center justify-center -mx-6'
        >
          {/* SVG lines overlay */}
          {containerRect && (
            <svg
              className='pointer-events-none absolute left-0 top-0 w-full h-full z-10'
              style={{
                width: containerRect.width,
                height: containerRect.height,
              }}
            >
              {lines.map((line, i) => (
                <line
                  key={i}
                  x1={line.x1}
                  y1={line.y1}
                  x2={line.x2}
                  y2={line.y2}
                  stroke='#7F8081'
                  strokeWidth={1}
                />
              ))}
            </svg>
          )}
          {/* Three columns */}
          <div
            className='flex-1 flex flex-col items-end gap-2 z-20 overflow-y-auto max-h-full'
            onScroll={handleColumnScroll}
          >
            {prelinks.map((dxid, i) => (
              <div
                key={dxid}
                ref={(el) => (prelinkRefs.current[i] = el)}
              >
                <RelationObjectItem
                  dxid={dxid}
                  selectedDxids={selectedDxids}
                  onSelect={handleSelect}
                />
              </div>
            ))}
          </div>
          <div className='flex-1 flex flex-col items-center z-20 mx-4'>
            <div ref={objectRef}>
              <RelationObjectItem
                dxid={documentObject?.dxid}
                selectedDxids={selectedDxids}
                onSelect={handleSelect}
              />
            </div>
          </div>
          <div
            className='flex-1 flex flex-col items-start gap-2 z-20 overflow-y-auto max-h-full'
            onScroll={handleColumnScroll}
          >
            {outlinks.map((dxid, i) => (
              <div
                key={dxid}
                ref={(el) => (outlinkRefs.current[i] = el)}
              >
                <RelationObjectItem
                  dxid={dxid}
                  selectedDxids={selectedDxids}
                  onSelect={handleSelect}
                />
              </div>
            ))}
          </div>
        </div>
        <RelationObjectItemCMenu id={relationObjectItemMenuId} />
      </DraggableModal>
    </ConfigProvider>
  );
};
